package com.xiaoshuidi.cloud.module.report.service.ajreport;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoshuidi.cloud.framework.common.pojo.PageResult;
import com.xiaoshuidi.cloud.framework.security.core.LoginUser;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderPayStatusEnum;
import com.xiaoshuidi.cloud.module.contract.enums.bill.OrderTypeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractNodeEnum;
import com.xiaoshuidi.cloud.module.contract.enums.contract.ContractOwnerStatusEnum;
import com.xiaoshuidi.cloud.module.report.controller.finance.vo.HouseOwnerDepositExportRespVO;
import com.xiaoshuidi.cloud.module.report.controller.finance.vo.HouseOwnerDepositReqVO;
import com.xiaoshuidi.cloud.module.report.controller.finance.vo.HouseOwnerDepositRespVO;
import com.xiaoshuidi.cloud.module.report.convert.finance.ReportHouseOwnerDepositConvert;
import com.xiaoshuidi.cloud.module.report.dal.DO.ContractOrderFeesDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.ReportContractRoomDepositDO;
import com.xiaoshuidi.cloud.module.report.dal.DO.report.ReportHouseOwnerDepositDO;
import com.xiaoshuidi.cloud.module.report.dal.mapper.ContractRentorderMapper;
import com.xiaoshuidi.cloud.module.report.dal.mapper.report.ReportHouseOwnerDepositMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.xiaoshuidi.cloud.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;

@Service
@RequiredArgsConstructor
@Slf4j
public class ReportHouseOwnerDepositServiceImpl implements ReportHouseOwnerDepositService {

    private final ContractRentorderMapper contractRentorderMapper;

    private final ReportHouseOwnerDepositMapper reportHouseOwnerDepositMapper;


    @Override
    public void dataProcessing() {
        Page<ReportHouseOwnerDepositDO> page = new Page<>(1, 100);
        report(page);
    }

    private void report(Page<ReportHouseOwnerDepositDO> page) {
        Page<ReportHouseOwnerDepositDO> pageList =
                reportHouseOwnerDepositMapper.selectPageListHouseOwner(page);
        List<ReportHouseOwnerDepositDO> records = pageList.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            //合同id集合
            List<Long> contractIds =
                    records.stream().map(ReportHouseOwnerDepositDO::getContractId).collect(Collectors.toList());
            //获取押金支付情况
            List<ContractOrderFeesDO> contractOrderFeesDOS =
                    contractRentorderMapper.selectOwnerDipositList(contractIds, OrderTypeEnum.OWNER.getCode());
            //获取押金退款情况
            List<ContractOrderFeesDO> returnOrderFeesDo =
                    contractRentorderMapper.selectOwnerDipositList(contractIds, OrderTypeEnum.OWNER_EVICTION.getCode());
            records.forEach(f -> {
                List<ContractOrderFeesDO> contractOrderDepositList =
                        contractOrderFeesDOS.stream().filter(c -> f.getContractId().equals(c.getContractId())).collect(Collectors.toList());
                //匹配到押金费项
                if (CollectionUtil.isNotEmpty(contractOrderDepositList)) {
                    f.setOutflowDeposit(contractOrderDepositList.stream().filter(of -> OrderPayStatusEnum.PAID.getCode().equals(of.getPayStatus())).map(ContractOrderFeesDO::getAmount)
                            .reduce(BigDecimal.ZERO, BigDecimal::add));
                } else {
                    //无流出押金明细
                    f.setOutflowDeposit(BigDecimal.ZERO);
                }
                //查看是否退租
                if (ContractOwnerStatusEnum.NORMAL_END.getCode().equals(f.getContractStatus())) {
                    //已结束 一般合同已续租  此时标记为已结束
                    if (!ContractNodeEnum.RENTING_OUT.getCode().equals(f.getContractNode())) {
                        f.setInflowDeposit(f.getOutflowDeposit());
                        f.setHandleFlag(1);
                    } else {
                        //查询退租单
                        List<ContractOrderFeesDO> contractReturnOrderDepositList =
                                returnOrderFeesDo.stream().filter(c -> f.getContractId().equals(c.getContractId())).collect(Collectors.toList());
                        //未查询到退租单一般为手动修改的数据
                        if (CollectionUtil.isNotEmpty(contractReturnOrderDepositList)) {
                            f.setInflowDeposit(contractReturnOrderDepositList.stream().filter(of -> OrderPayStatusEnum.PAID.getCode().equals(of.getPayStatus())).map(ContractOrderFeesDO::getPaidAmount)
                                    .reduce(BigDecimal.ZERO, BigDecimal::add));
                            //付款了算完结
                            if (contractReturnOrderDepositList.stream().filter(of -> OrderPayStatusEnum.PAID.getCode().equals(of.getPayStatus())).count() > 0) {
                                f.setHandleFlag(1);
                            }
                        } else {
                            f.setInflowDeposit(f.getOutflowDeposit());
                            f.setHandleFlag(1);
                        }
                    }
                }
            });

            List<ReportHouseOwnerDepositDO> reportHouseOwnerDepositDOS =
                    reportHouseOwnerDepositMapper.selectList(ReportHouseOwnerDepositDO::getContractId, contractIds);
            List<Long> oldContractIds =
                    reportHouseOwnerDepositDOS.stream().map(ReportHouseOwnerDepositDO::getContractId).collect(Collectors.toList());
            //新增
            List<ReportHouseOwnerDepositDO> addList =
                    records.stream().filter(f -> CollectionUtil.isEmpty(oldContractIds) || oldContractIds.stream().filter(ol->ol.compareTo(f.getContractId())==0).count() == 0)
                            .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(addList)) {
                log.info("新增{}=============", addList.size());
                reportHouseOwnerDepositMapper.insertBatch(addList);
            }
            //修改
            List<ReportHouseOwnerDepositDO> updateList =
                    records.stream().filter(f -> CollectionUtil.isNotEmpty(oldContractIds) &&  oldContractIds.stream().filter(ol->ol.compareTo(f.getContractId())==0).count() > 0)
                            .peek(p -> {
                                reportHouseOwnerDepositDOS.stream().filter(fb -> fb.getContractId().compareTo(p.getContractId())==0).findFirst().ifPresent(ip -> {
                                    p.setId(ip.getId());
                                });
                            })
                            .collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(updateList)) {
                log.info("修改{}=============", updateList.size());
                reportHouseOwnerDepositMapper.updateBatch(updateList, updateList.size());
            }

            //数据处理结束
            //递归处理
            if (records.size() == page.getSize()) {
                page.setCurrent(page.getCurrent() + 1);
                report(page);
            }

        }
    }

    @Override
    public HouseOwnerDepositRespVO page(HouseOwnerDepositReqVO reqVO) {
        LoginUser loginUser = getLoginUser();
        if (ObjectUtil.isNotNull(loginUser)) {
            reqVO.setTenantId(loginUser.getTenantId());
//            reqVO.setTenantId(10000L);
        }
        HouseOwnerDepositRespVO vo = new HouseOwnerDepositRespVO();
        vo.setPageResult(ReportHouseOwnerDepositConvert.INSTANCE.convertPageResult(selectPageList(reqVO)));
        //统计
        QueryWrapper<ReportHouseOwnerDepositDO> queryWrapper = new QueryWrapper<ReportHouseOwnerDepositDO>()
                .select("\tSUM( inflow_deposit ) amountIn,\n" +
                        "\tSUM( outflow_deposit ) amountOut,\n" +
                        "\tSUM( inflow_deposit ) - SUM( outflow_deposit ) amountReduce")
                .ge(ObjectUtil.isNotNull(reqVO.getStart()), "create_time", reqVO.getStart())
                .le(ObjectUtil.isNotNull(reqVO.getEnd()), "create_time", reqVO.getEnd())
                .eq(ObjectUtil.isNotNull(reqVO.getTenantId()), "tenant_id", reqVO.getTenantId())
                .in(CollectionUtil.isNotEmpty(reqVO.getApartmentIds()), "apartment_id", reqVO.getApartmentIds())
                .like(StrUtil.isNotEmpty(reqVO.getOwnerName()), "owner_name", reqVO.getOwnerName())
                .like(StrUtil.isNotEmpty(reqVO.getPhone()), "phone", reqVO.getPhone());
        List<Map<String, Object>> maps = reportHouseOwnerDepositMapper.selectMaps(queryWrapper);
        if (CollectionUtil.isNotEmpty(maps) && ObjectUtil.isNotNull(maps.get(0))) {
            vo.setAmountIn(ObjectUtil.isNotNull(maps.get(0).get("amountIn")) ? new BigDecimal(maps.get(0).get(
                    "amountIn").toString()) : BigDecimal.ZERO);
            vo.setAmountOut(ObjectUtil.isNotNull(maps.get(0).get("amountOut")) ? new BigDecimal(maps.get(0).get(
                    "amountOut").toString()) : BigDecimal.ZERO);
            vo.setAmountReduce(ObjectUtil.isNotNull(maps.get(0).get("amountReduce")) ?
                    new BigDecimal(maps.get(0).get("amountReduce").toString()) : BigDecimal.ZERO);
        }
        return vo;
    }

    @Override
    public PageResult<ReportHouseOwnerDepositDO> selectPageList(HouseOwnerDepositReqVO reqVO) {
        LambdaQueryWrapper<ReportHouseOwnerDepositDO> queryWrapper =
                new LambdaQueryWrapper<ReportHouseOwnerDepositDO>()
                        .ge(ObjectUtil.isNotNull(reqVO.getStart()), ReportHouseOwnerDepositDO::getCreateTime,
                                reqVO.getStart())
                        .le(ObjectUtil.isNotNull(reqVO.getEnd()), ReportHouseOwnerDepositDO::getCreateTime,
                                reqVO.getEnd())
                        .eq(ObjectUtil.isNotNull(reqVO.getTenantId()), ReportHouseOwnerDepositDO::getTenantId,
                                reqVO.getTenantId())
                        .in(CollectionUtil.isNotEmpty(reqVO.getApartmentIds()),
                                ReportHouseOwnerDepositDO::getApartmentId,
                                reqVO.getApartmentIds())
                        .like(StrUtil.isNotEmpty(reqVO.getOwnerName()), ReportHouseOwnerDepositDO::getOwnerName,
                                reqVO.getOwnerName())
                        .like(StrUtil.isNotEmpty(reqVO.getPhone()), ReportHouseOwnerDepositDO::getPhone,
                                reqVO.getPhone())
                        .orderByDesc(ReportHouseOwnerDepositDO::getCreateTime, ReportHouseOwnerDepositDO::getId);
        PageResult<ReportHouseOwnerDepositDO> reportContractRoomDepositDOPageResult =
                reportHouseOwnerDepositMapper.selectPage(reqVO, queryWrapper);
        return reportContractRoomDepositDOPageResult;
    }
}
